﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using DomainDriver.DomainModeling.DomainObjects;
using DomainDriver.DomainModeling.Events;
using DomainDriver.DomainModeling.Exceptions;
using DomainDriver.DomainModeling.Queries;
using DomainDriver.DomainModeling.StorageManagers;

namespace DomainDriver.DomainModeling.Repositories
{
    public partial class Repository<KEY, KEYED_DOMAIN_OBJECT>
    {
        #region Assertion Support

        protected void AssertDomainObjectNotNull(KEYED_DOMAIN_OBJECT domainObject)
        {
            if (domainObject == null)
            {
                string message = string.Format("The specified \"{0}\" instance is null.", InfoProvider.DomainObjectClassName);
                throw new ApplicationException(message);
            }
        }

        protected void AssertDomainObjectExistence(KEYED_DOMAIN_OBJECT domainObject, bool shouldExist)
        {
            if (Exists(domainObject.Key) != shouldExist)
            {
                string message = string.Format("The key \"{0}\" already exists in the {1} repository.", domainObject.Key.ToString(), InfoProvider.DomainObjectClassName);
                throw new ApplicationException(message);
            }
        }

        protected void AssertDomainObjectExistsInRepository(KEYED_DOMAIN_OBJECT domainObject)
        {
            AssertDomainObjectExistence(domainObject, true);
        }

        protected void AssertDomainObjectDoesNotExistInRepository(KEYED_DOMAIN_OBJECT domainObject)
        {
            AssertDomainObjectExistence(domainObject, false);
        }

        protected void GenerateObjectManagementException(Exception exception, StackTrace stackTrace)
        {
            int repositoryFrameNumber = 0;
            string className = InfoProvider.RepositoryClassShortName;
            string methodName = stackTrace.GetFrame(repositoryFrameNumber).GetMethod().Name;
            string message = string.Format("Call to method \"{0}.{1}\" failed.", className, methodName);
            throw new DomainObjectManagementException(message, exception);
        }

        #endregion

        #region Event Support

        protected void DispatchAddingEvent(KEYED_DOMAIN_OBJECT domainObject)
        {
            if (AddingDomainObject == null)
            { return; }

            AddDomainObjectEventArgs<KEY, KEYED_DOMAIN_OBJECT> args = new AddDomainObjectEventArgs<KEY, KEYED_DOMAIN_OBJECT>(domainObject);
            AddingDomainObject(this, args);
        }

        protected void DispatchAddedEvent(KEYED_DOMAIN_OBJECT domainObject)
        {
            if (AddedDomainObject == null)
            { return; }

            AddDomainObjectEventArgs<KEY, KEYED_DOMAIN_OBJECT> args = new AddDomainObjectEventArgs<KEY, KEYED_DOMAIN_OBJECT>(domainObject);
            AddedDomainObject(this, args);
        }

        protected void DispatchRemovingEvent(KEYED_DOMAIN_OBJECT domainObject)
        {
            if (RemovingDomainObject == null)
            { return; }

            RemoveDomainObjectEventArgs<KEY, KEYED_DOMAIN_OBJECT> args = new RemoveDomainObjectEventArgs<KEY, KEYED_DOMAIN_OBJECT>(domainObject);
            RemovingDomainObject(this, args);
        }

        protected void DispatchRemovedEvent(KEYED_DOMAIN_OBJECT domainObject)
        {
            if (RemovedDomainObject == null)
            { return; }

            RemoveDomainObjectEventArgs<KEY, KEYED_DOMAIN_OBJECT> args = new RemoveDomainObjectEventArgs<KEY, KEYED_DOMAIN_OBJECT>(domainObject);
            RemovedDomainObject(this, args);
        }

        protected void DispatchUpdatingEvent(KEYED_DOMAIN_OBJECT originalDomainObject, KEYED_DOMAIN_OBJECT updatedDomainObject)
        {
            if (UpdatingDomainObject == null)
            { return; }

            UpdateDomainObjectEventArgs<KEY, KEYED_DOMAIN_OBJECT> args = new UpdateDomainObjectEventArgs<KEY, KEYED_DOMAIN_OBJECT>(originalDomainObject, updatedDomainObject);
            UpdatingDomainObject(this, args);
        }

        protected void DispatchUpdatedEvent(KEYED_DOMAIN_OBJECT originalDomainObject, KEYED_DOMAIN_OBJECT updatedDomainObject)
        {
            if (UpdatedDomainObject == null)
            { return; }

            UpdateDomainObjectEventArgs<KEY, KEYED_DOMAIN_OBJECT> args = new UpdateDomainObjectEventArgs<KEY, KEYED_DOMAIN_OBJECT>(originalDomainObject, updatedDomainObject);
            UpdatedDomainObject(this, args);
        }

        #endregion
    }
}